package com.ydzh.kfqgwvisitor.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.aliyuncs.exceptions.ClientException;
import com.baidu.aip.face.AipFace;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.ydzh.kfqgwvisitor.base.Result;
import com.ydzh.kfqgwvisitor.common.Constant;
import com.ydzh.kfqgwvisitor.constant.Configure;
import com.ydzh.kfqgwvisitor.constant.VisitorAppointmentURL;
import com.ydzh.kfqgwvisitor.dto.PeerPeopleDTO;
import com.ydzh.kfqgwvisitor.dto.VisitorDTO;
import com.ydzh.kfqgwvisitor.dto.VisitorExcelDTO;
import com.ydzh.kfqgwvisitor.dto.VisitorFaceDTO;
import com.ydzh.kfqgwvisitor.entity.BeDepartment;
import com.ydzh.kfqgwvisitor.entity.BeUnit;
import com.ydzh.kfqgwvisitor.entity.BeVisitor;
import com.ydzh.kfqgwvisitor.entity.Visitor;
import com.ydzh.kfqgwvisitor.enums.PictureCheckEnum;
import com.ydzh.kfqgwvisitor.exception.BaseException;
import com.ydzh.kfqgwvisitor.hikdata.hikreq.person.Person;
import com.ydzh.kfqgwvisitor.hikdata.hikreq.visitor.VisitorInfo;
import com.ydzh.kfqgwvisitor.hikdata.hikres.person.PersonData;
import com.ydzh.kfqgwvisitor.hikdata.hikres.person.PersonList;
import com.ydzh.kfqgwvisitor.hikdata.hikres.person.PersonPhotoRes;
import com.ydzh.kfqgwvisitor.hikdata.hikres.visitor.VisitorData;
import com.ydzh.kfqgwvisitor.mapper.VisitorMapper;
import com.ydzh.kfqgwvisitor.properties.BaiDuProperties;
import com.ydzh.kfqgwvisitor.properties.Properties;
import com.ydzh.kfqgwvisitor.response.Response;
import com.ydzh.kfqgwvisitor.service.BeDepartmentService;
import com.ydzh.kfqgwvisitor.service.BeUnitService;
import com.ydzh.kfqgwvisitor.service.BeVisitorService;
import com.ydzh.kfqgwvisitor.service.VisitorService;
import com.ydzh.kfqgwvisitor.tool.GetCameraPreviewURL;
import com.ydzh.kfqgwvisitor.util.*;
import com.ydzh.kfqgwvisitor.vo.IDCardVo;
import com.ydzh.kfqgwvisitor.vo.PeerPeopleVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 访客信息表  服务实现类
 * </p>
 *
 * @author zcj
 * @since 2021-09-01
 */
@Slf4j
@Service
public class VisitorServiceImpl extends ServiceImpl<VisitorMapper, Visitor> implements VisitorService {
    private static final long CAPTCHA_OUT_TIME = 60 * 1000;
    private static final String ID_CARD_KEY = "{}:{}:idCard";
    private static final String FACE_KEY = "{}:{}:face";
    @Autowired
    private VisitorMapper mapper;
    @Autowired
    private BaiDuProperties baiDuProperties;

    @Autowired
    private BeVisitorService beVisitorService;
    @Autowired
    private BeUnitService beUnitService;
    @Autowired
    private BeDepartmentService beDepartmentService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result saveToApply(VisitorDTO visitorDTO) {
        // 判断预约时间时候大于当前时间
        if (visitorDTO.getAppointmentEndTime().isBefore(LocalDateTime.now())) {
            return Result.buildError("预约结束时间不能小于当前时间");
        }
        Visitor visitor = BeanUtil.copyProperties(visitorDTO, Visitor.class);
        log.info("主访客进行保存:{}", visitor.getVisitorName());
        LocalDateTime now = LocalDateTime.now();
        visitor.setCreateTime(now);
        visitor.setFollowNum(visitorDTO.getPeerPeopleList().size());
        // 判断手机号
        if (!PhoneUtil.isPhone(visitor.getPhoneNo())) {
            return Result.buildError("主访客手机号格式不正确，请重新填报");
        }
        // 进行身份证与姓名进行比对
        Properties idcardName = baiDuProperties.getIdcardName();
        AipFace aipFace = new AipFace(idcardName.getAppId(), idcardName.getApiKey(), idcardName.getSecretKey());
        org.json.JSONObject jsonObject = aipFace.idMatch(visitor.getIdCardNo(), visitor.getVisitorName(), null);
        if (jsonObject.getInt("error_code") != 0) {
            return Result.buildError("主访客身份证与姓名不匹配，请重新填报");
        }
        visitor.setVisitorImg(visitor.getVisitorImg().split(",")[1]);
        // 压缩头像在保存
        /*try {
            visitor.setVisitorImg(PicUtils.saveMinPhoto(visitor.getVisitorImg().split(",")[1], 640, 1d));
        } catch (Exception e) {
            e.printStackTrace();
            return Result.buildError("头像压缩失败，请稍后重试");
        }*/
        save(visitor);
        List<Visitor> visitorList = new ArrayList<>();
        log.info("陪同人员人数为：{}", visitorDTO.getPeerPeopleList().size());
        if (CollectionUtil.isNotEmpty(visitorDTO.getPeerPeopleList())) {
            for (PeerPeopleDTO peerPeopleDTO : visitorDTO.getPeerPeopleList()) {
                Visitor peerVisitor = BeanUtil.copyProperties(peerPeopleDTO, Visitor.class);
                peerVisitor.setAppointmentStartTime(visitor.getAppointmentStartTime());
                peerVisitor.setAppointmentEndTime(visitor.getAppointmentEndTime());
                peerVisitor.setBevisitorId(visitor.getBevisitorId());
                peerVisitor.setBevisitorName(visitor.getBevisitorName());
                peerVisitor.setBeunitId(visitorDTO.getBeunitId());
                peerVisitor.setBeunitName(visitorDTO.getBeunitName());
                peerVisitor.setFaceAuth(1);
                // 判断手机号
                if (!PhoneUtil.isPhone(peerVisitor.getPhoneNo())) {
                    String error = "陪同人员:{},手机号格式不正确，请重新填报";
                    throw new BaseException(-1, String.format(error, peerVisitor.getVisitorName()));
                }
                peerVisitor.setLeaderId(visitor.getId());
                peerVisitor.setCreateTime(now);
                if (StrUtil.isBlank(peerVisitor.getIdCardNo()) || StrUtil.isBlank(peerVisitor.getVisitorName())) {
                    throw new BaseException(-1, "陪同人员的身份证和姓名不能为空");
                }
                org.json.JSONObject result = aipFace.idMatch(peerVisitor.getIdCardNo(), peerVisitor.getVisitorName(), null);
                if (result.getInt("error_code") != 0) {
                    String error = "陪同人员:{},身份证与姓名不匹配";
                    throw new BaseException(-1, String.format(error, peerVisitor.getVisitorName()));
                }
                visitorList.add(peerVisitor);
            }
            saveBatch(visitorList);
            // 循环给陪同人员发短信，进行录脸
            for (Visitor visitor1 : visitorList) {
                Map<String, String> map = new LinkedHashMap<>(2);
                map.put("userId", visitor1.getId().toString());
                try {
                    AliSmsUtils.sendSms(visitor1.getPhoneNo(), Constant.SMS_PEER_CODE, map);
                } catch (ClientException e) {
                    e.printStackTrace();
                    String error = "因陪同人员短信发送失败，本次申请失败，请稍后重试";
                    throw new BaseException(-1, error);
                }
            }
        } else {
            Map<String, String> map = new LinkedHashMap<>(1);
            map.put("userId", visitor.getId().toString());
            try {
                // 通过领导的ID查询手机号
                BeVisitor beVisitor = beVisitorService.getById(visitor.getBevisitorId());
                map.put("userName", beVisitor.getBevisitorName());
                log.info("给领导发短信：{}", beVisitor.getPhoneNo());
                AliSmsUtils.sendSms(beVisitor.getPhoneNo(), Constant.SMS_LEADER_CODE, map);
            } catch (ClientException e) {
                e.printStackTrace();
                return Result.buildError("信息发送失败，请稍后重试");
            }
        }


        return Result.buildSuccess();
    }


    @Override
    public Result<com.ydzh.kfqgwvisitor.vo.VisitorVO> visitorInfo(Long visitorId) {
        // 先获得主访客的信息
        Visitor visitor = getById(visitorId);
        com.ydzh.kfqgwvisitor.vo.VisitorVO visitorVO = BeanUtil.copyProperties(visitor, com.ydzh.kfqgwvisitor.vo.VisitorVO.class);
        if (!visitorVO.getState().equals("0")) {
            return Result.buildError("此申请已审批");
        }
        // 查找随从人员
        List<Visitor> visitorList = query().eq("LEADER_ID", visitorId).list();
        List<PeerPeopleVO> peerPeopleVOList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(visitorList)) {
            for (Visitor visitor1 : visitorList) {
                PeerPeopleVO peerPeopleVO = BeanUtil.copyProperties(visitor1, PeerPeopleVO.class);
                peerPeopleVOList.add(peerPeopleVO);
            }
            visitorVO.setPeerPeopleList(peerPeopleVOList);
        }
        return Result.buildSuccess(visitorVO);
    }

    @Override
    public Result<IDCardVo> idCardInfo(String img, HttpServletRequest request) {
        // 获得用户的ip
        String ipAddr = CommonUtil.getIpAddr(request);
        log.info("获得用户的ip：{}", ipAddr);
        // 获得用户浏览器的User-Agent
        String header = request.getHeader("User-Agent");
        log.info(" 获得用户浏览器的User-Agent：{}", header);
        // 将上面的进行MD5加密
        String md5Key = CommonUtil.MD5(StrUtil.format(FACE_KEY, ipAddr, header));
        // 判断redis的key是否存在
        if (stringRedisTemplate.hasKey(md5Key)) {
            Long increment = stringRedisTemplate.opsForValue().increment(md5Key);
            if (increment.intValue() >= 5L) {
                return Result.buildError("操作太快了，请稍后再试");
            }
            stringRedisTemplate.expire(md5Key, CAPTCHA_OUT_TIME, TimeUnit.MILLISECONDS);
        } else {
            stringRedisTemplate.opsForValue().set(md5Key, "1", CAPTCHA_OUT_TIME, TimeUnit.MILLISECONDS);
        }
        if (StrUtil.isBlank(img)) {
            return Result.buildError("照片不能为空");
        }
        Properties ioc = baiDuProperties.getIoc();
        IdcardUtil idTest = new IdcardUtil(ioc.getAppId(), ioc.getApiKey(), ioc.getSecretKey());
        HashMap<String, String> options = new HashMap<>(2);
        options.put("detect_direction", "true");
        options.put("detect_risk", "true");
        JSONObject jsonObject = idTest.idcard(img, "front", options);
        if (jsonObject.has("error_msg")) {
            return Result.buildError("身份证解析失败，请重新上传");
        }
        JSONObject words_result = jsonObject.getJSONObject("words_result");
        if (Objects.isNull(words_result)) {
            return Result.buildError("身份证解析失败，请重新上传");
        }
        IDCardVo idCardVo = new IDCardVo();
        idCardVo.setUserName(words_result.getJSONObject("姓名").get("words").toString());
        if (StringUtils.isBlank(idCardVo.getUserName())) {
            return Result.buildError("身份证姓名解析失败，请重新上传");
        }
        String gender = words_result.getJSONObject("性别").get("words").toString();
        if (StringUtils.isBlank(gender)) {
            return Result.buildError("身份证性别解析失败，请重新上传");
        }
        idCardVo.setGender("男".equals(gender) ? 1 : 2);

        idCardVo.setIdCard(words_result.getJSONObject("公民身份号码").get("words").toString());
        if (StringUtils.isBlank(idCardVo.getIdCard())) {
            return Result.buildError("身份证身份证号解析失败，请重新上传");
        }
        return Result.buildSuccess(idCardVo);
    }

    @Override
    public Result faceverify(String img, HttpServletRequest request) {


        String imgBase64 = img.split(",")[1];
       /* String imageTo2M = null;
        try {
            imageTo2M = PicUtils.saveMinPhoto(imgBase64, 640, 1d);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.buildError("图片压缩失败，请稍后重试。");
        }*/
        byte[] decode = Base64.getDecoder().decode(imgBase64);
        int length = decode.length;
        log.info("前端传来的长度为：{}，转换为KB：{},转换M为：{}", length, length / 1024, length / 1024 / 1024);
        // 调用海康进行人脸评分
        Map<String, String> pictureCheck = faceScore(imgBase64);
        // apiCode 若是200 证明是调用海康设备成功
        if ("200".equals(pictureCheck.get("apiCode"))) {
            // 人脸评分，若为true证明成功，否则证明失败
            if (!"true".equals(pictureCheck.get("checkResult"))) {
                // log.info("图片的base64：{}", img);
                return Result.buildError(PictureCheckEnum.getMsg(pictureCheck.get("checkResult")));
            }
            // 证明是调用海康设备失败
        } else {
            // log.info("图片的base64：{}", img);
            return Result.buildError("照片评分过低，请调整手机的远近距离！");
        }

        // 获得用户的ip
       /* String ipAddr = CommonUtil.getIpAddr(request);
        log.info("获得用户的ip：{}", ipAddr);
        // 获得用户浏览器的User-Agent
        String header = request.getHeader("User-Agent");
        log.info(" 获得用户浏览器的User-Agent：{}", header);
        // 将上面的进行MD5加密
        String md5Key = CommonUtil.MD5(StrUtil.format(ID_CARD_KEY, ipAddr, header));
        // 判断redis的key是否存在
        if (stringRedisTemplate.hasKey(md5Key)) {
            Long increment = stringRedisTemplate.opsForValue().increment(md5Key);
            if (increment.intValue() >= 12L) {
                return Result.buildError("操作太快了，请稍后再试");
            }
            stringRedisTemplate.expire(md5Key, CAPTCHA_OUT_TIME, TimeUnit.MILLISECONDS);
        } else {
            stringRedisTemplate.opsForValue().set(md5Key, "1", CAPTCHA_OUT_TIME, TimeUnit.MILLISECONDS);
        }*/
        // log.info("压缩后String的长度为：{}", imgBase64.length());
        // String[] split = imageTo7M.split(",");
        // todo 临时注释掉活体认证
        /*Properties idcardName = baiDuProperties.getIdcardName();
        AipFace aipFace = new AipFace(idcardName.getAppId(), idcardName.getApiKey(), idcardName.getSecretKey());
        FaceVerifyRequest faceVerifyRequest = new FaceVerifyRequest(imgBase64, "BASE64");
        List<FaceVerifyRequest> input = new ArrayList<>();
        input.add(faceVerifyRequest);
        JSONObject faceverify = aipFace.faceverify(input);
        log.info("百度的返回值为：{}", faceverify);
        if (faceverify.getInt("error_code") != 0) {
            System.out.println("认证失败");
            return Result.buildError("认证失败，请重新拍照");
        }
        if (faceverify.getJSONObject("result").getBigDecimal("face_liveness").compareTo(new BigDecimal("0.90")) == -1) {
            log.info("百度的存活率为：{}", faceverify.getJSONObject("result").getBigDecimal("face_liveness"));
            return Result.buildError("认证失败，请重新拍照");
        }*/

        return Result.buildSuccess();
    }


    /**
     * 通过QRCode查询访客来访记录v2中的访客id(orderId)
     * <p>
     * 这个用作二维码失效之后重新生成二维码(此功能现在不需要 如果需要还需要海康生成访客动态二维码内容联合查询)
     *
     * @param QRCode
     * @return
     */
/*    @Override
    public String orderIdByQRCode(String QRCode) {

        GetCameraPreviewURL cameraPreviewURL = new GetCameraPreviewURL(Configure.host, Configure.appKey, Configure.appSecret);

        VisitorRecords visitorRecords = new VisitorRecords();

        visitorRecords.setPageNo(1);

        visitorRecords.setPageSize(999);

        visitorRecords.setQRCode(QRCode);

        //海康查询访客来访记录v2 获取访客id
        String s = cameraPreviewURL.doPost(GetCameraPreviewURL.ARTEMIS_PATH + VisitorAppointmentURL.QUERY_VISITOR_RECORDS, JSON.toJSONString(visitorRecords));

        net.sf.json.JSONObject jsonObjectP = net.sf.json.JSONObject.fromObject(s);

        Map<String, Class> classMap = new HashMap<>();

        //组装海康门禁返回数据
        classMap.put("data", RecordsData.class);

        classMap.put("list", RecordsList.class);

        classMap.put("designatedResources", DesignatedResources.class);

        Result recordsResult = (Result) net.sf.json.JSONObject.toBean(jsonObjectP, Result.class, classMap);

        RecordsData data = (RecordsData) recordsResult.getData();

        List<RecordsList> list = data.getList();

        String orderId = "";

        for (RecordsList rl : list) {
            orderId = rl.getOrderId();
        }

        return orderId;
    }*/

    /**
     * 通过身份证号查询访客信息
     *
     * @param idCardNo
     * @return
     */
    @Override
    public Visitor getByIdCardNo(String idCardNo) {

        return baseMapper.getByIdCardNo(idCardNo);
    }

    /**
     * 点击链接生成访客二维码
     * 返回二维码创建时间及二维码图片的base64是否全程接种疫苗和健康码颜色
     *
     * @param id
     * @return
     */
/*    @Override
    public Response getQRCode(Long id) {

        Response response = new Response();

        String qrCode = baseMapper.selectById(id).getQRCode();

        if (StringUtils.isNotBlank(qrCode)) {

            String base64Img = BufferedImageToBase64(qrCodeToBufferImage(qrCode));

            response.setQTime(dateTimeFormatter.format(baseMapper.selectById(id).getCreateTime()));

            response.setBase64(base64Img);

            return response;
        }
        List<String> strings = QRCode(id);

        //领导点击同意之后海康返回QRCode的时间
        for (String qr : strings) {

            LambdaQueryWrapper<Visitor> wrapper = new LambdaQueryWrapper<>();

            wrapper.eq(Visitor::getQRCode, qr);

            Visitor one = getOne(wrapper);

            response.setQTime(dateTimeFormatter.format(one.getCreateTime()));

            String base64Img = BufferedImageToBase64(qrCodeToBufferImage(qr));

            response.setBase64(base64Img);

        }

        return response;

    }*/

    /**
     * 生成海康二维码
     *
     * @param id
     * @return
     */
    @Override
    public Response getQRCode(Long id) {

        Response response = new Response();

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");

        Visitor visitor = baseMapper.selectById(id);

        if (Objects.nonNull(visitor)) {

            String qrCode = visitor.getQRCode();

            if (org.apache.commons.lang3.StringUtils.isNotBlank(qrCode)) {

                String base64Img = "data:image/jpg;base64," + BufferedImageToBase64(qrCodeToBufferImage(qrCode));

                response.setQTime(dateTimeFormatter.format(visitor.getCreateTime()));

                response.setBase64(base64Img);

            }

        }

        return response;

    }

    /**
     * 增加海康返回的二维码内容到数据库中
     *
     * @param id
     * @return
     */
    @Override
    public Boolean addQrCode(Long id) {

      /*  DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");

        String qrCode = baseMapper.selectById(id).getQRCode();

        if (StringUtils.isNotBlank(qrCode)) {

            String base64Img = BufferedImageToBase64(qrCodeToBufferImage(qrCode));

            response.setQTime(dateTimeFormatter.format(baseMapper.selectById(id).getCreateTime()));

            response.setBase64(base64Img);

            return response;
        }*/

        //同意的情况下每次都是新增，所以不用到本地库里在去查询有没有qrCode
        List<String> strings = QRCode(id);

        if (CollectionUtil.isNotEmpty(strings)) {

            return true;

        }

        return false;

    }

    /**
     * 点击链接生成访客卫健委
     *
     * @param id
     * @return
     * @throws Exception
     */
    @Override
    public Response getHealthCode(Long id) {

        Response response = new Response();

        //山东省疫苗接种和核酸检测信息查询服务
        response.setFlag(getVaccination(id));

        //获取健康码颜色
        response.setState(getPassCodeColor(id));

        return response;
    }

    /**
     * 把qrCode转成BufferedImage
     *
     * @param qrCode
     * @return
     */
    private BufferedImage qrCodeToBufferImage(String qrCode) {

        //生成二维码配置
        HashMap<EncodeHintType, Object> hints = new HashMap<>();

        //设置纠错等级
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);

        //编码类型
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

        BitMatrix bitMatrix;

        BufferedImage bufferedImage = null;

        try {

            bitMatrix = new MultiFormatWriter().encode(qrCode, BarcodeFormat.QR_CODE, 300, 300, hints);

            //把矩阵写入图像
            bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);

        } catch (WriterException e) {

            e.printStackTrace();

        }

        return bufferedImage;
    }

    /**
     * BufferedImage 编码转换为 base64
     *
     * @param bufferedImage
     * @return
     */
    private String BufferedImageToBase64(BufferedImage bufferedImage) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
        try {
            ImageIO.write(bufferedImage, "jpg", baos);//写入流中
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] bytes = baos.toByteArray();//转换成字节

        String png_base64 = Base64.getEncoder().encodeToString(bytes).trim();//转换成base64串
        png_base64 = png_base64.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\n
        //return 为jpg格式则写jpg ;png则写png
        return png_base64;
    }

    /**
     * 获取健康码状态
     *
     * @return
     */
    @Override
    public Integer getPassCode(Long id) {

        String apiKeyHealth = "879756510412931072";

        String appIdHealth = "iao4p1fjbq37misom68w";

        String appSecretHealth = "24f8875c9c7d45419acde17d88bb8b62";

        // String urlHealth = "http://59.224.6.2/gateway/api/3/checkVaccineStatusExt";
        String urlHealth = "http://172.168.1.224:80/gateway/api/3/checkVaccineStatusExt";

        cn.hutool.json.JSONObject common = Common(apiKeyHealth, appIdHealth, appSecretHealth, urlHealth, id);

        Integer status = (Integer) common.getJSONObject("data").getJSONObject("data").getJSONObject("data").get("status");

        return status;
    }

    /**
     * 山东省疫苗接种和核酸检测信息查询服务
     *
     * @param id
     * @return
     */
    @Override
    public Integer getVaccination(Long id) {

        String apiKeyHealth = "879756809923985408";

        String appIdHealth = "iao4p1fjbq37misom68w";

        String appSecretHealth = "24f8875c9c7d45419acde17d88bb8b62";

        String urlHealth = "http://172.168.1.224:80/gateway/api/11/getVaccineRecordExt";
        // String urlHealth = "http://59.224.6.2/gateway/api/11/getVaccineRecordExt";

        cn.hutool.json.JSONObject common = Common(apiKeyHealth, appIdHealth, appSecretHealth, urlHealth, id);

        Integer flag = (Integer) common.getJSONObject("data").getJSONObject("data").getJSONObject("data").get("flag");

        return flag;
    }

    /**
     * 获取健康码颜色
     *
     * @param id
     * @return
     */
    @Override
    public Integer getPassCodeColor(Long id) {

        String appIdHealth = "iao4p1fjbq37misom68w";

        String appSecretHealth = "24f8875c9c7d45419acde17d88bb8b62";

        String urlHealth = "http://172.168.1.224:80/passDataExchangeService/dataExchange/getHealthPassByUserInfo";
        // String urlHealth = "http://172.20.238.8:4431/passDataExchangeService/dataExchange/getHealthPassByUserInfo";

        cn.hutool.json.JSONObject common1 = Common1(appIdHealth, appSecretHealth, urlHealth, id);

        //是否有健康码：true，有；false，无
        Boolean is = (Boolean) common1.getJSONObject("data").get("isHaveHealthCode");

        if (is) {

            //健康码等级： 0，绿色； 1，黄色； 2，红色；
            Integer state = (Integer) common1.getJSONObject("data").get("state");

            return state;
        }
        //如果集合为空则代表此人没有健康码
        return null;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result upload(MultipartFile multipartFile) {
        beDepartmentService.deleteAll();
        beVisitorService.deleteAll();
        ImportParams params = new ImportParams();
        // 头部有两行
        params.setHeadRows(2);
        // params.setStartSheetIndex(0);
        params.setSheetNum(8);
        // params.setTitleRows(0);
        List<VisitorExcelDTO> result = null;
        try {
            result = ExcelImportUtil.importExcel(multipartFile.getInputStream(),
                    VisitorExcelDTO.class, params);
        } catch (Exception e) {
            e.printStackTrace();
        }

        List<BeVisitor> visitorList = new ArrayList<>();
        int num = 0;
        for (VisitorExcelDTO visitorExcelDTO : result) {
            // 先查询单位的ID(查一次即可)
            BeUnit unit = beUnitService.query().eq("BEUNIT_NAME", visitorExcelDTO.getUnit().trim()).one();
            if (Objects.isNull(unit)) {
                throw new BaseException(-1, "部门不存在,excel部门获得为" + visitorExcelDTO.getUnit().trim());
            }
            if (StringUtils.isBlank(visitorExcelDTO.getName()) || StringUtils.isBlank(visitorExcelDTO.getPhone())) {
                continue;
            }
            num++;
            System.out.println(unit.getBeunitId());
            System.out.println(visitorExcelDTO.getDept());
            // 在查询部门是否存在
            BeDepartment department = beDepartmentService.query().eq("BEUNIT_ID", unit.getBeunitId()).eq("DEPARTMENT_NAME", visitorExcelDTO.getDept().trim()).one();
            // 若存在就就保存人员
            if (Objects.nonNull(department)) {
                log.info("进入人员的保存");
                BeVisitor beVisitor = new BeVisitor();
                beVisitor.setBevisitorName(visitorExcelDTO.getName());
                beVisitor.setDeptId(department.getBedepartmentId());
                beVisitor.setPhoneNo(visitorExcelDTO.getPhone().trim());
                visitorList.add(beVisitor);
            } else {
                log.info("进入部门的保存");
                // 若不存在就先保存部门再保存人员
                BeDepartment departmentNew = new BeDepartment();
                departmentNew.setDepartmentName(visitorExcelDTO.getDept().trim());
                departmentNew.setBeunitId(unit.getBeunitId());
                beDepartmentService.save(departmentNew);
                BeVisitor beVisitor = new BeVisitor();
                beVisitor.setBevisitorName(visitorExcelDTO.getName().trim());
                beVisitor.setDeptId(departmentNew.getBedepartmentId());
                beVisitor.setPhoneNo(visitorExcelDTO.getPhone().trim());
                visitorList.add(beVisitor);
            }

        }
        beVisitorService.saveBatch(visitorList);
        System.out.println(num + ".........................");
        return Result.buildSuccess();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result applyFace(VisitorFaceDTO visitorFaceDTO, HttpServletRequest request) {
        // 获得陪同人员
        Visitor visitor = getById(visitorFaceDTO.getId());
        log.info("陪同人员进行活体认证:{}", visitor.getVisitorName());
        if (ObjectUtil.isNull(visitor)) {
            return Result.buildError("参数错误");
        }
        if (StringUtils.isNotBlank(visitor.getVisitorImg())) {
            return Result.buildError("你已完成认证请勿操作");
        }
        // log.info("图片的base64前100:{}", visitorFaceDTO.getVisitorImg().substring(0, 100));
        String imgBase64 = visitorFaceDTO.getVisitorImg().split(",")[1];

        /*String imageTo2M = null;
        try {
            imageTo2M = PicUtils.saveMinPhoto(imgBase64, 640, 1d);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.buildError("图片压缩失败，请稍后重试。");
        }*/
        byte[] decode = Base64.getDecoder().decode(imgBase64);
        int length = decode.length;
        log.info("前端传来的长度为：{}，转换为KB：{},转换M为：{}", length, length / 1024, length / 1024 / 1024);
        // 调用海康进行人脸评分
        Map<String, String> pictureCheck = faceScore(imgBase64);
        // apiCode 若是200 证明是调用海康设备成功
        if ("200".equals(pictureCheck.get("apiCode"))) {
            // 人脸评分，若为true证明成功，否则证明失败
            if (!"true".equals(pictureCheck.get("checkResult"))) {
                return Result.buildError(PictureCheckEnum.getMsg(pictureCheck.get("checkResult")));
            }
            // 证明是调用海康设备失败
        } else {
            return Result.buildError("照片评分过低，请调整手机的远近距离！");
        }
        // TODO 临时关闭活体认证
       /* // 获得用户的ip
        String ipAddr = CommonUtil.getIpAddr(request);
        log.info("获得用户的ip：{}", ipAddr);
        // 获得用户浏览器的User-Agent
        String header = request.getHeader("User-Agent");
        log.info(" 获得用户浏览器的User-Agent：{}", header);
        // 将上面的进行MD5加密
        String md5Key = CommonUtil.MD5(StrUtil.format(ID_CARD_KEY, ipAddr, header));
        // 判断redis的key是否存在
        if (stringRedisTemplate.hasKey(md5Key)) {
            Long increment = stringRedisTemplate.opsForValue().increment(md5Key);
            if (increment.intValue() >= 12L) {
                return Result.buildError("操作太快了，请稍后再试");
            }
            stringRedisTemplate.expire(md5Key, CAPTCHA_OUT_TIME, TimeUnit.MILLISECONDS);
        } else {
            stringRedisTemplate.opsForValue().set(md5Key, "1", CAPTCHA_OUT_TIME, TimeUnit.MILLISECONDS);
        }

        // log.info("压缩有base64前100：{}", imgBase64.substring(0, 100));
        Properties idcardName = baiDuProperties.getIdcardName();
        AipFace aipFace = new AipFace(idcardName.getAppId(), idcardName.getApiKey(), idcardName.getSecretKey());
        FaceVerifyRequest faceVerifyRequest = new FaceVerifyRequest(imgBase64, "BASE64");
        List<FaceVerifyRequest> input = new ArrayList<>();
        input.add(faceVerifyRequest);
        JSONObject faceverify = aipFace.faceverify(input);
        log.info("百度的返回值为：{}", faceverify);
        log.info("百度的存活率为：{}", faceverify.getJSONObject("result").getBigDecimal("face_liveness"));
        if (faceverify.getInt("error_code") != 0) {
            System.out.println("认证失败");
            return Result.buildError("认证失败，请重新拍照");
        }
        if (faceverify.getJSONObject("result").getBigDecimal("face_liveness").compareTo(new BigDecimal("0.90")) == -1) {
            return Result.buildError("认证失败，请重新拍照");
        }*/
        log.info("进行陪同人图片:{} 更新", visitor.getVisitorName());
        update().eq("ID", visitorFaceDTO.getId()).set("VISITOR_IMG", imgBase64).update();
        log.info("进行陪同人图片:{} 更新完成", visitor.getVisitorName());
        // 获得主访客的陪同人员
        Visitor mainVisitor = getById(visitor.getLeaderId());
        log.info("主访客:{} 查询成功，ID为：{}", mainVisitor.getVisitorName(), mainVisitor.getId());
        mainVisitor.setFollowFaceNum(mainVisitor.getFollowFaceNum() + 1);
        // 若随从人员人脸书别通过数量等于随从人员,并且预约开始时间大于今天
        if (mainVisitor.getFollowNum().intValue() == mainVisitor.getFollowFaceNum().intValue()) {
            // 若预约结束时间在当前时间之后,才能发送端短信给领导
            if (mainVisitor.getAppointmentEndTime().isAfter(LocalDateTime.now())) {
                log.info("所有人员完成人脸识别:", mainVisitor.getId());
                Map<String, String> map = new LinkedHashMap<>(2);
                map.put("userId", mainVisitor.getId().toString());
                try {
                    log.info("查询领导数据，用来发送短信：{}", mainVisitor.getBevisitorId());
                    // 通过领导的ID查询手机号
                    BeVisitor beVisitor = beVisitorService.getById(mainVisitor.getBevisitorId());
                    map.put("userName", beVisitor.getBevisitorName());
                    log.info("领导信息查询成功，给领导手机号为：{}", beVisitor.getPhoneNo());
                    AliSmsUtils.sendSms(beVisitor.getPhoneNo(), Constant.SMS_LEADER_CODE, map);
                    log.info("领导短信发送成功");
                } catch (ClientException e) {
                    e.printStackTrace();
                    throw new BaseException(-1, "信息发送失败，请稍后重试");
                }
            } else {
                mainVisitor.setState("0");
                log.info("所有人脸认证完成，但时间失效", mainVisitor.getPhoneNo());
                return Result.buildSuccess("时间失效，请联系发起访客人重新申请");
            }

        }
        updateById(mainVisitor);
        log.info("主访客{} 更新完成,id为：{}", mainVisitor.getVisitorName(), mainVisitor.getId());
        return Result.buildSuccess();
    }

    @Override
    public Result passFaceCheck(Long id) {
        Visitor visitor = getById(id);
        if (Objects.isNull(visitor)) {
            return Result.buildError("此人员不存在");
        }
        if (StrUtil.isNotBlank(visitor.getVisitorImg())) {
            return Result.buildError("你完成人脸录入");
        }
        return Result.buildSuccess();
    }

    @Override
    public Result restartApplyFace(VisitorFaceDTO visitorFaceDTO) {
        Boolean hasKey = stringRedisTemplate.hasKey(visitorFaceDTO.getId().toString());
        if (!hasKey) {
            return Result.buildError("你已完成认证请勿操作");
        }
        // 获得陪同人员
        Visitor visitor = getById(visitorFaceDTO.getId());
        log.info("陪同人员进行活体认证:{}", visitor.getVisitorName());
        if (ObjectUtil.isNull(visitor)) {
            return Result.buildError("参数错误");
        }
        // log.info("图片的base64前100:{}", visitorFaceDTO.getVisitorImg().substring(0, 100));
        String imgBase64 = visitorFaceDTO.getVisitorImg().split(",")[1];

        /*String imageTo2M = null;
        try {
            imageTo2M = PicUtils.saveMinPhoto(imgBase64, 640, 1d);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.buildError("图片压缩失败，请稍后重试。");
        }*/
        byte[] decode = Base64.getDecoder().decode(imgBase64);
        int length = decode.length;
        log.info("前端传来的长度为：{}，转换为KB：{},转换M为：{}", length, length / 1024, length / 1024 / 1024);
        // 调用海康进行人脸评分
        Map<String, String> pictureCheck = faceScore(imgBase64);
        // apiCode 若是200 证明是调用海康设备成功
        if ("200".equals(pictureCheck.get("apiCode"))) {
            // 人脸评分，若为true证明成功，否则证明失败
            if (!"true".equals(pictureCheck.get("checkResult"))) {
                return Result.buildError(PictureCheckEnum.getMsg(pictureCheck.get("checkResult")));
            }
            // 证明是调用海康设备失败
        } else {
            return Result.buildError("照片评分过低，请调整手机的远近距离！");
        }

        // log.info("压缩有base64前100：{}", imgBase64.substring(0, 100));
        // todo 临时关闭活体认证
        /*Properties idcardName = baiDuProperties.getIdcardName();
        AipFace aipFace = new AipFace(idcardName.getAppId(), idcardName.getApiKey(), idcardName.getSecretKey());
        FaceVerifyRequest faceVerifyRequest = new FaceVerifyRequest(imgBase64, "BASE64");
        List<FaceVerifyRequest> input = new ArrayList<>();
        input.add(faceVerifyRequest);
        JSONObject faceverify = aipFace.faceverify(input);
        log.info("百度的返回值为：{}", faceverify);
        log.info("百度的存活率为：{}", faceverify.getJSONObject("result").getBigDecimal("face_liveness"));
        if (faceverify.getInt("error_code") != 0) {
            System.out.println("认证失败");
            return Result.buildError("认证失败，请重新拍照");
        }
        if (faceverify.getJSONObject("result").getBigDecimal("face_liveness").compareTo(new BigDecimal("0.90")) == -1) {
            return Result.buildError("认证失败，请重新拍照");
        }*/
        log.info("进行陪同人图片:{} 更新", visitor.getVisitorName());
        update().eq("ID", visitorFaceDTO.getId()).set("VISITOR_IMG", imgBase64).update();
        log.info("进行陪同人图片:{} 更新完成", visitor.getVisitorName());
        // todo 调用海康接口完成录入
        visitor.setVisitorImg(imgBase64);
        Boolean saveToHK = addSinglePerson(visitor);
        if (saveToHK) {
            // 最后发送短信给重新录入的人员
            Map<String, String> map = new LinkedHashMap<>(2);
            map.put("userId", visitor.getId().toString());

            try {
                AliSmsUtils.sendSms(visitor.getPhoneNo(), Constant.SMS_VISITOR_SUCCESSCODE, map);
            } catch (ClientException e) {
                String error = "短信发送失败，请稍后重试";
                throw new BaseException(-2, error);
            }
            // 删除Redis的key
            stringRedisTemplate.delete(visitorFaceDTO.getId().toString());
            return Result.buildSuccess();
        } else {
            return Result.buildError("人脸录入失败，请重新拍照");
        }

    }

    /**
     * 通过海康查询访客来访记录v2查询到访客的id
     *
     * @param phoneNo 手机号
     * @return
     */
    private List<String> getOrderId(String phoneNo) {

        GetCameraPreviewURL cameraPreviewURL = new GetCameraPreviewURL(Configure.host, Configure.appKey, Configure.appSecret);

        com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();

        jsonObject.put("phoneNo", phoneNo);

        jsonObject.put("pageNo", 1);

        jsonObject.put("pageSize", 1);

        //查询访客来访记录
        String s = cameraPreviewURL.doPost(GetCameraPreviewURL.ARTEMIS_PATH + VisitorAppointmentURL.QUERY_VISITOR_RECORDS, JSON.toJSONString(jsonObject));

        log.info("查询访客在海康人员列表信息 s={}", s);

        com.alibaba.fastjson.JSONObject getOrderId = JSON.parseObject(s);

        if ("0".equals(getOrderId.getString("code"))) {

            com.alibaba.fastjson.JSONObject data = getOrderId.getJSONObject("data");
            log.info("海康返回值json为：{}", s);

            final com.alibaba.fastjson.JSONArray list = data.getJSONArray("list");

            List<String> orderIds = new ArrayList<>();

            for (int i = 0; i < list.size(); i++) {

                com.alibaba.fastjson.JSONObject j = list.getJSONObject(i);

                String orderId = j.getString("orderId");

                log.info("访客在海康平台的id={}", orderId);

                orderIds.add(orderId);

            }

            return orderIds;
        }

        return null;
    }

    /**
     * 访客签离
     *
     * @param phoneNo 已预约成功的访客的手机号
     * @return
     */
    private List<Boolean> visitorCheckOut(String phoneNo) {

        List<String> orderIds = this.getOrderId(phoneNo);

        if (!CollectionUtils.isEmpty(orderIds)) {

            List<Boolean> booleans = new ArrayList<>();

            for (String orderId : orderIds) {

                GetCameraPreviewURL cameraPreviewURL = new GetCameraPreviewURL(Configure.host, Configure.appKey, Configure.appSecret);

                com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();

                jsonObject.put("orderId", orderId);

                //查询访客来访记录
                String s = cameraPreviewURL.doPost(GetCameraPreviewURL.ARTEMIS_PATH + VisitorAppointmentURL.VISITOR_CHECK_OUT, JSON.toJSONString(jsonObject));

                com.alibaba.fastjson.JSONObject visitorCheckOut = JSON.parseObject(s);

                if ("0".equals(visitorCheckOut.getString("code"))) {

                    booleans.add(true);

                }

                return booleans;

            }
        }
        return null;
    }

    /**
     * 定时签离数据库的访客 一分钟一次
     *
     * @return
     */
    @Scheduled(fixedRate = 60000)
    public void regularCheckOut() {

        //查出预约成功的访客
        List<Visitor> visitors = baseMapper.selectList(new LambdaQueryWrapper<Visitor>().eq(Visitor::getState, "1"));

        // log.info("预约状态为成功的对象集合 visitors={}", visitors);

        if (!CollectionUtils.isEmpty(visitors)) {

            for (Visitor visitor : visitors) {

                //当前时间大于访客填写的出去的时间就给他签出
                if (visitor.getAppointmentEndTime().isBefore(LocalDateTime.now())) {

                    List<Boolean> booleans = this.visitorCheckOut(visitor.getPhoneNo());

                    log.info("海康平台潜力成功的人的手机号 PhoneNo:{},海康的返回值为：{}", visitor.getPhoneNo(), booleans);
                    if (CollectionUtil.isNotEmpty(booleans)) {
                        log.info("集合不为空，进入循环");
                        for (int i = 0; i < booleans.size(); i++) {

                            if (true == booleans.get(i)) {
                                log.info("有值为true");
                                visitor.setState("3");

                                baseMapper.updateById(visitor);

                            }
                        }
                    }

                }
            }

        }
    }


    /**
     * 卫计委通用方法1
     *
     * @param apiKeyHealth
     * @param appIdHealth
     * @param appSecretHealth
     * @param urlHealth
     * @param id
     * @return
     */
    private cn.hutool.json.JSONObject Common(String apiKeyHealth, String appIdHealth, String appSecretHealth, String urlHealth, Long id) {
        //大数据局申请的apiKey，该部分需要替换
        String apiKey = apiKeyHealth;
        HttpHeaders headers = new HttpHeaders();
        headers.set("ApiKey", apiKey);
        //电子健康卡/码分配的授权，该部分需要替换
        String appId = appIdHealth;
        //电子健康卡/码分配的密钥，该部分需要替换
        String appSecret = appSecretHealth;

        RestTemplate restTemplate = new RestTemplate();
        //政务网地址
        String url = urlHealth;

        //组装参数
        cn.hutool.json.JSONObject paramJsonData = new cn.hutool.json.JSONObject();

        Visitor visitor = baseMapper.selectById(id);

        List<cn.hutool.json.JSONObject> jsonObjects = new ArrayList<>();

        paramJsonData.set("name", HealthCommissionUtils.encByAES(visitor.getVisitorName()));

        paramJsonData.set("cardNo", HealthCommissionUtils.encByAES(visitor.getIdCardNo()));
        //个人信息与二维码，二选一填写
        //paramJsonData.set("qrCode", "714C0A2AD6E603A755DBD0CA23FBBB63E6C8F7B999A99BF8E884B9B5D5930FCA:0:748FD3A74A91EC4CF95::");
        LinkedMultiValueMap<String, Object> linkedMap = new LinkedMultiValueMap<>();
        //生成时间戳
        String time = "" + System.currentTimeMillis();
        //生成随机字符串
        String nonceStr = RandomUtil.randomString(10);
        //获得签名值
        String str = appId + "&" + time + "&" + nonceStr;

        String sign = HealthCommissionUtils.genHMAC(str, appSecret);
        //将签名值添加到参数中
        linkedMap.add("sign", sign);

        linkedMap.add("appid", appId);

        linkedMap.add("nonce_str", nonceStr);

        linkedMap.add("time", time);

        linkedMap.add("paramJsonData", paramJsonData);

        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity(linkedMap, headers);
        //调用接口
        cn.hutool.json.JSONObject result = restTemplate.postForEntity(url, httpEntity, cn.hutool.json.JSONObject.class).getBody();

        return result;
    }

    /**
     * 卫健委通用方法2
     *
     * @param appIdHealth
     * @param appSecretHealth
     * @param urlHealth
     * @param id
     * @return
     */
    private cn.hutool.json.JSONObject Common1(String appIdHealth, String appSecretHealth, String urlHealth, Long id) {

        //电子健康卡/码分配的授权，该部分需要替换
        String appId = appIdHealth;
        //电子健康卡/码分配的密钥，该部分需要替换
        String appSecret = appSecretHealth;

        RestTemplate restTemplate = new RestTemplate();
        //政务网地址
        String url = urlHealth;

        //组装参数
        cn.hutool.json.JSONObject paramJsonData = new cn.hutool.json.JSONObject();

        Visitor visitor = baseMapper.selectById(id);

        List<cn.hutool.json.JSONObject> jsonObjects = new ArrayList<>();

        paramJsonData.set("outside", 0);

        paramJsonData.set("cardType", "01");

        paramJsonData.set("name", HealthCommissionUtils.encByAES(visitor.getVisitorName()));

        paramJsonData.set("cardNo", HealthCommissionUtils.encByAES(visitor.getIdCardNo()));
        //个人信息与二维码，二选一填写
        //paramJsonData.set("qrCode", "714C0A2AD6E603A755DBD0CA23FBBB63E6C8F7B999A99BF8E884B9B5D5930FCA:0:748FD3A74A91EC4CF95::");
        LinkedMultiValueMap<String, Object> linkedMap = new LinkedMultiValueMap<>();
        //生成时间戳
        String time = "" + System.currentTimeMillis();
        //生成随机字符串
        String nonceStr = RandomUtil.randomString(10);
        //获得签名值
        String str = appId + "&" + time + "&" + nonceStr;
        String sign = HealthCommissionUtils.genHMAC(str, appSecret);
        //将签名值添加到参数中
        linkedMap.add("sign", sign);
        linkedMap.add("appid", appId);
        linkedMap.add("nonce_str", nonceStr);
        linkedMap.add("time", time);
        linkedMap.add("paramJsonData", paramJsonData);
        //调用接口
        cn.hutool.json.JSONObject result = restTemplate.postForEntity(url, linkedMap, cn.hutool.json.JSONObject.class).getBody();

        return result;
    }


    /**
     * 通过leaderId查找随行访客信息
     *
     * @param id
     * @return
     */
    @Override
    public List<Visitor> getVisitorByLeaderId(Long id) {
        return baseMapper.getVisitorByLeaderId(id);
    }

    /**
     * 被访人确认
     * <p>
     * 首先把访客信息插入海康数据库中，然后海康返回二维码内容，把这个内容插入到本地数据库中
     * 发短信给访客
     *
     * @param id 主访客id
     * @return
     */
    @Override
    public Result confirm(Long id) {

        //第一步是把从海康平台获取的qrCode插入数据库(如果露脸成功)海康平台就会返回此qrCode，否则则不会
        Boolean result = addQrCode(id);

        //qrCode插入本地数据库成功之后，则会给访客发送成功信息
        if (result == true) {

            Visitor mainVisitor = baseMapper.selectById(id);

            if (Objects.nonNull(mainVisitor)) {

                //1是成功
                baseMapper.updateById(mainVisitor.setState("1"));

            } else {

                return Result.buildError("用户不存在！");
            }

            List<Visitor> visitorByLeader = baseMapper.getVisitorByLeaderId(id);

            if (!CollectionUtils.isEmpty(visitorByLeader)) {

                //1是成功
                visitorByLeader.forEach(visitor -> baseMapper.updateById(visitor.setState("1")));

            }

            //更改完数据库状态之后挨个给方可发短信通知预约成功
            List<Visitor> visitor = getVisitor(id);

            for (Visitor v : visitor) {

                // todo 短信模板需要更改
                Map<String, String> map = new LinkedHashMap<>(2);

                map.put("userId", v.getId().toString());

                try {

                    AliSmsUtils.sendSms(v.getPhoneNo(), Constant.SMS_VISITOR_SUCCESSCODE, map);

                } catch (ClientException e) {

                    e.printStackTrace();

                    String error = "短信发送失败，请稍后重试";

                    throw new BaseException(-2, error);

                }

            }

            return Result.buildSuccess();

        }

        return Result.buildError("操作成功，但访客信息录入海康数据失败，已发送短信给访客重新录入。");

    }

    /**
     * 被访人拒绝访客申请
     * <p>
     * 发短信给访客
     *
     * @param id 主访客id
     * @return
     */
    @Override
    public Result refuse(Long id) {

        Visitor mainVisitor = baseMapper.selectById(id);

        if (Objects.nonNull(mainVisitor)) {

            //2是失败
            baseMapper.updateById(mainVisitor.setState("2"));

        } else {

            return Result.buildError("用户不存在！");
        }

        List<Visitor> visitorByLeader = baseMapper.getVisitorByLeaderId(id);

        if (!CollectionUtils.isEmpty(visitorByLeader)) {

            //2是失败
            visitorByLeader.forEach(visitor -> baseMapper.updateById(visitor.setState("2")));

        }

        //更改完数据库状态之后挨个给方可发短信通知预约成功
        List<Visitor> visitor = getVisitor(id);

        for (Visitor v : visitor) {

            // todo 短信模板需要更改
            Map<String, String> map = new LinkedHashMap<>(2);
            // map.put("userId", v.getId().toString());

            try {

                AliSmsUtils.sendSms(v.getPhoneNo(), Constant.SMS_VISITOR_FAILCODE, map);

            } catch (ClientException e) {

                e.printStackTrace();

                String error = "短信发送失败，请稍后重试";

                throw new BaseException(-2, error);

            }

        }

        return Result.buildSuccess();
    }

    /**
     * 通过被访人姓名调取海康接口(查询人员列表v2)
     * <p>
     * 被访人id 通过数据库的id找到被访人的名字  在通过被访人的名字找到海康平台上被访人的id(被访人的名字只找到一个)   已过
     *
     * @param id
     * @return
     */
    @Override
    public String personId(Long id) {

        GetCameraPreviewURL cameraPreviewURL = new GetCameraPreviewURL(Configure.host, Configure.appKey, Configure.appSecret);

        Person person = new Person();

        //从我们的数据库里通过访客id关联查到被访人姓名
        String beVisitorName = getBevisitorName(id);

        person.setPersonName(beVisitorName);

        person.setPageNo(1);

        person.setPageSize(999);

        //海康查询人员列表v2(在海康平台里通过被访人行名查到被访人id)
        String s = cameraPreviewURL.doPost(GetCameraPreviewURL.ARTEMIS_PATH + VisitorAppointmentURL.QUERY_PERSON_LIST, JSON.toJSONString(person));

        net.sf.json.JSONObject jsonObjectP = net.sf.json.JSONObject.fromObject(s);

        Map<String, Class> classMap = new HashMap<>();

        //组装海康门禁返回数据
        classMap.put("data", PersonData.class);

        classMap.put("list", PersonList.class);

        classMap.put("personPhoto", PersonPhotoRes.class);

        Result personResult = (Result) net.sf.json.JSONObject.toBean(jsonObjectP, Result.class, classMap);

        PersonData data = (PersonData) personResult.getData();

        List<PersonList> list = data.getList();

        String personId = "";

        for (PersonList p : list) {
            personId = p.getPersonId();
        }
        return personId;
    }

    /**
     * 获取访客二维码信息
     * <p>
     * 海康预约免登记接口
     *
     * @param receptionistId
     * @return
     */
    @Override
    public List<String> QRCode(Long receptionistId) {

        GetCameraPreviewURL cameraPreviewURL = new GetCameraPreviewURL(Configure.host, Configure.appKey, Configure.appSecret);

        List<Visitor> visitorList = getVisitor(receptionistId);

        List<com.ydzh.kfqgwvisitor.hikdata.hikreq.visitor.Visitor> visitors = new ArrayList<>();

        //通过海康平台查到被访人id
        String rd = personId(receptionistId);
        Map<String, Long> map = new HashMap<>(visitorList.size());

        for (Visitor vv : visitorList) {

            com.ydzh.kfqgwvisitor.hikdata.hikreq.visitor.Visitor visitor = new com.ydzh.kfqgwvisitor.hikdata.hikreq.visitor.Visitor();
            map.put(vv.getIdCardNo(), vv.getId());
            visitor.setReceptionistId(rd);

            visitor.setVisitStartTime(TimeUtils.getISO8601ToStr(vv.getAppointmentStartTime()));

            //取出访客填写的拜访结束时间
            LocalDateTime appointmentEndTime = vv.getAppointmentEndTime();

            if (appointmentEndTime.isBefore(LocalDateTime.now())) {

                throw new BaseException(-3, "预约时间已失效！");
            }

            visitor.setVisitEndTime(TimeUtils.getISO8601ToStr(appointmentEndTime));

            VisitorInfo visitorInfo = new VisitorInfo();

            visitorInfo.setVisitorName(vv.getVisitorName());

            visitorInfo.setGender(Integer.valueOf(vv.getSex()));

            visitorInfo.setPhoneNo(vv.getPhoneNo());

            visitorInfo.setCertificateNo(vv.getIdCardNo());

            //来访车牌号
            visitorInfo.setPlateNo(vv.getVehicleNo());

            //证件类型为身份证
            visitorInfo.setCertificateType(111);

            //加入卡号，配合海康测试！！！！！
            visitorInfo.setCardNo("YD" + vv.getIdCardNo());

            //修改前
            //String visitorImg = baseMapper.getVisitorImg(receptionistId);

            //修改后
            String visitorImg = vv.getVisitorImg();

            visitorInfo.setVisitorPhoto(visitorImg);

            visitor.setVisitorInfo(visitorInfo);

            visitors.add(visitor);

        }

        List<String> qrCodeList = new ArrayList<>();

        for (com.ydzh.kfqgwvisitor.hikdata.hikreq.visitor.Visitor v : visitors) {

            //海康预约免登记
            String s = cameraPreviewURL.doPost(GetCameraPreviewURL.ARTEMIS_PATH + VisitorAppointmentURL.RESERVATION_FREE_REGISTRATION, JSON.toJSONString(v));
            log.error("海康的返回值为：{}", s);

            net.sf.json.JSONObject jsonObjectP = net.sf.json.JSONObject.fromObject(s);

            if ("0x0531401d".equals(jsonObjectP.get("code"))) {

                throw new BaseException(-2, "预约时间冲突！请重新选择预约时间！");

            }

            if ("0x0531f025".equals(jsonObjectP.get("code")) || "0x0240100a".equals(jsonObjectP.get("code"))) {

                //String failVisitor = stringRedisTemplate.opsForValue().get(receptionistId);

                //if (StringUtils.isBlank(failVisitor)) {

                //访客录脸失败,发送短信让他重新露脸，只录入一次，再次失败页面上会有提醒
                sendFailMessage(receptionistId);
                continue;
                //} else {

                //throw new BaseException(-2, "图片质量太低");
                //}

            }

            Map<String, Class> classMap = new HashMap<>();

            //组装海康返回数据
            classMap.put("data", VisitorData.class);

            Result personResult = (Result) net.sf.json.JSONObject.toBean(jsonObjectP, Result.class, classMap);

            VisitorData data = (VisitorData) personResult.getData();
            log.error("data.getQRCode()的data为：{}", data);
            String qrCode = data.getQRCode();

            //通过证件号码找到访客并与之qrCode进行绑定

            Visitor byIdCardNo = baseMapper.selectById(map.get(v.getVisitorInfo().getCertificateNo()));

            byIdCardNo.setQRCode(qrCode);

            //把带有qrCode的访客插入数据库
            baseMapper.updateById(byIdCardNo);

            //插入海康平台成功之后删除此key
            //stringRedisTemplate.delete(v.getReceptionistId());

            qrCodeList.add(qrCode);
        }

        //返回qrCode集合
        return qrCodeList;
    }

    /**
     * 根据id查找被访人姓名
     *
     * @param id
     * @return
     */
    @Override
    public String getBevisitorName(Long id) {

        return baseMapper.getBevisitorName(id);
    }

    /**
     * 通过访客id获取Visitor集合(包括主访客和随行访客)
     *
     * @param id
     * @return
     */
    private List<Visitor> getVisitor(Long id) {

        List<Visitor> visitorList = new ArrayList<>();

        //查找主访客
        visitorList.add(baseMapper.selectById(id));

        //随行访客list
        for (Visitor visitor : getVisitorByLeaderId(id)) {

            visitorList.add(visitor);

        }
        return visitorList;
    }

    /**
     * 海康人脸评分接口
     *
     * @param facePicBinaryData
     * @return
     */
    public static Map<String, String> faceScore(String facePicBinaryData) {

        GetCameraPreviewURL cameraPreviewURL = new GetCameraPreviewURL(Configure.host, Configure.appKey, Configure.appSecret);

        net.sf.json.JSONObject jsonObject = new net.sf.json.JSONObject();

        jsonObject.put("facePicBinaryData", facePicBinaryData);

        //jsonObject.put("facePicUrl","");

        String s = cameraPreviewURL.doPost(GetCameraPreviewURL.ARTEMIS_PATH + VisitorAppointmentURL.FACE_SCORE, JSON.toJSONString(jsonObject));

        net.sf.json.JSONObject jsonObjectS = net.sf.json.JSONObject.fromObject(s);
        log.info("海康的人脸评分返回的信息：{}", jsonObjectS);

        /*Map<String, Class> classMap = new HashMap<>();

        //组装海康门禁返回数据
        classMap.put("data", ScoreData.class);

        classMap.put("facePicAnalysisResult", FacePicAnalysisResult.class);

        classMap.put("facePose", FacePose.class);

        classMap.put("faceRect", FaceRect.class);

        classMap.put("recommendFaceRect", RecommendFaceRect.class);

        classMap.put("faceMark", FaceMark.class);

        classMap.put("leftEye", LeftEye.class);

        classMap.put("rightEye", RightEye.class);

        classMap.put("noseTip", NoseTip.class);

        classMap.put("leftMouth", LeftMouth.class);

        classMap.put("rightMouth", RightMouth.class);

        Result scoreResult = (Result) net.sf.json.JSONObject.toBean(jsonObjectS, Result.class, classMap);

        ScoreData data = (ScoreData) scoreResult.getData();

        String statusCode = data.getStatusCode();*/
        Map<String, String> map = new HashMap<>();

        net.sf.json.JSONObject result = jsonObjectS.getJSONObject("data");

        log.info("海康的人脸评分返回的信息,获得的data为：{}", result);
        //接口调用成功
        if ("0".equals(jsonObjectS.getString("code")) && result.getBoolean("checkResult") == false) {

            map.put("apiCode", "200"); //调用海康接口成功

            map.put("checkResult", result.getString("statusCode")); //评分失败详细错误码，

        }
        if ("0".equals(jsonObjectS.getString("code")) && result.getBoolean("checkResult") == true) {

            Integer score = (Integer) result.get("faceScore");

            log.info("海康人脸评分接口返回的人脸评分 score:{}", score);

            if (score < 50) {
                // log.error("图片审核失败的额base64：{}", facePicBinaryData);

                throw new BaseException(-2, "照片评分过低，请调整手机的远近距离！");

            }

            map.put("apiCode", "200"); //调用海康接口成功

            map.put("checkResult", "true"); //人脸图片检测结果，评分合格

        }
        /*传入一张人脸图片，检测人脸图片是否合格，注意，人脸评分是检测人脸质量的辅助手段，只有人脸评分失败（返回错误码0x1f913016）时才认为是人脸图片不合格，其它情况如调用超时等情况，图片只是未检测，不能作为人脸不可用的依据。*/
        if ("0x1f913016".equals(jsonObjectS.getString("code")) && result.getBoolean("checkResult") == false) {

            map.put("apiCode", "200"); //调用海康接口成功

            map.put("checkResult", result.getString("statusCode")); //人脸图片检测结果，评分合格

        }


        if (!"0".equals(jsonObjectS.getString("code"))) {

            map.put("apiCode", "201"); //调用海康接口失败

            map.put("checkResult", ""); //注意 调用海康接口失败没有此值
        }

        return map;
    }

    /**
     * 录脸失败，给失败的人发短信要求器重新录入
     *
     * @param id
     */
    public void sendFailMessage(Long id) {

        Visitor mainVisitor = baseMapper.selectById(id);

        if (Objects.nonNull(mainVisitor)) {

            //2是失败
            baseMapper.updateById(mainVisitor.setState("2"));

        } else {

            throw new BaseException(-3, "访客不存在！");
        }

        List<Visitor> visitorByLeader = baseMapper.getVisitorByLeaderId(id);

        if (!CollectionUtils.isEmpty(visitorByLeader)) {

            //2是失败
            visitorByLeader.forEach(visitor -> baseMapper.updateById(visitor.setState("2")));

        }

        //更改完数据库状态之后挨个给方可发短信通知预约成功
        List<Visitor> visitor = getVisitor(id);

        for (Visitor v : visitor) {

            // todo 短信模板需要更改
            Map<String, String> map = new LinkedHashMap<>(2);

            map.put("userId", v.getId().toString());

            try {

                //此短信模板是访客录脸失败需要给访客发短信，只发一次，再次失败之后页面上会有提醒再次重新录入
                AliSmsUtils.sendSms(v.getPhoneNo(), Constant.SMS_HIK_VISITOR_FAILCODE, map);

                //发完短信之后把他存入redis 这里设置key和value一样
                stringRedisTemplate.opsForValue().set(v.getId().toString(), v.getId().toString());

            } catch (ClientException e) {

                e.printStackTrace();

                String error = "短信发送失败，请稍后重试";

                throw new BaseException(-2, error);

            }
        }

    }

    /**
     * 单个人重新露脸插入海康平台中
     * 成功返回true
     *
     * @param visitor
     * @return
     */
    public Boolean addSinglePerson(Visitor visitor) {

        GetCameraPreviewURL cameraPreviewURL = new GetCameraPreviewURL(Configure.host, Configure.appKey, Configure.appSecret);

        Visitor singlePerson = baseMapper.selectById(visitor.getId());

        if (Objects.nonNull(singlePerson)) {

            //通过海康平台查到被访人id
            String rd = personId(visitor.getId());

            com.ydzh.kfqgwvisitor.hikdata.hikreq.visitor.Visitor hikVisitor = new com.ydzh.kfqgwvisitor.hikdata.hikreq.visitor.Visitor();

            hikVisitor.setReceptionistId(rd);

            hikVisitor.setVisitStartTime(TimeUtils.getISO8601ToStr(singlePerson.getAppointmentStartTime()));

            hikVisitor.setVisitEndTime(TimeUtils.getISO8601ToStr(singlePerson.getAppointmentEndTime()));

            VisitorInfo visitorInfo = new VisitorInfo();

            visitorInfo.setVisitorName(singlePerson.getVisitorName());

            visitorInfo.setGender(Integer.valueOf(singlePerson.getSex()));

            visitorInfo.setPhoneNo(singlePerson.getPhoneNo());

            visitorInfo.setCertificateNo(singlePerson.getIdCardNo());

            //来访车牌号
            visitorInfo.setPlateNo(singlePerson.getVehicleNo());

            //证件类型为身份证
            visitorInfo.setCertificateType(111);

            //加入卡号，配合海康测试！！！！！
            visitorInfo.setCardNo(singlePerson.getIdCardNo());

            visitorInfo.setVisitorPhoto(singlePerson.getVisitorImg());

            hikVisitor.setVisitorInfo(visitorInfo);

            //海康预约免登记
            String s = cameraPreviewURL.doPost(GetCameraPreviewURL.ARTEMIS_PATH + VisitorAppointmentURL.RESERVATION_FREE_REGISTRATION, JSON.toJSONString(hikVisitor));
            log.error("海康的返回值为：{}", s);

            net.sf.json.JSONObject jsonObjectP = net.sf.json.JSONObject.fromObject(s);

            if ("0x0531401d".equals(jsonObjectP.get("code"))) {

                throw new BaseException(-2, "预约时间冲突！请重新选择预约时间！");

            }

            if ("0x0531f025".equals(jsonObjectP.get("code")) || "0x0240100a".equals(jsonObjectP.get("code"))) {

                //String failVisitor = stringRedisTemplate.opsForValue().get(id);

                //if (StringUtils.isBlank(failVisitor)) {

                //访客录脸失败,发送短信让他重新露脸，只录入一次，再次失败页面上会有提醒
                //sendFailMessage(visitor.getId());
                throw new BaseException(-2, "图片质量太低,请重新录入");

                //} else {

                //throw new BaseException(-2, "图片质量太低");
                // }

            }

            Map<String, Class> classMap = new HashMap<>();

            //组装海康返回数据
            classMap.put("data", VisitorData.class);

            Result personResult = (Result) net.sf.json.JSONObject.toBean(jsonObjectP, Result.class, classMap);

            VisitorData data = (VisitorData) personResult.getData();
            log.error("data.getQRCode()的data为：{}", data);
            String qrCode = data.getQRCode();

            //通过证件号码找到访客并与之qrCode进行绑定
            Visitor byIdCardNo = baseMapper.selectById(visitor.getId());

            byIdCardNo.setQRCode(qrCode);

            //把带有qrCode的访客插入数据库
            baseMapper.updateById(byIdCardNo);

            //插入海康平台成功之后删除此key
            //stringRedisTemplate.delete(String.valueOf(visitor.getId()));

            return true;

        }

        return false;
    }

    /**
     * 测试卫健委接口
     *
     * @param args
     */
    public static void main(String[] args) {

        /*String s = "{\n" +
                "    \"code\": \"0\",\n" +
                "    \"msg\": \"success\",\n" +
                "    \"data\": {\n" +
                "        \"total\": 1,\n" +
                "        \"pageNo\": 1,\n" +
                "        \"pageSize\": 20,\n" +
                "        \"list\": [\n" +
                "            {\n" +
                "                \"visitorName\": \"张三\",\n" +
                "                \"gender\": 1,\n" +
                "                \"certificateType\": 111,\n" +
                "                \"certificateNo\": \"311256196602145692\",\n" +
                "                \"phoneNo\": \"13576361254\",\n" +
                "                \"plateNo\": \"浙A12345\",\n" +
                "                \"picUri\": \"/pic?adsdqwe21-asafdd-12sfsdfsdf\",\n" +
                "                \"svrIndexCode\": \"sadsa123-asd21edsfhgsd-23rfdvsr\",\n" +
                "                \"visitorStatus\": 8,\n" +
                "                \"verificationCode\": \"1234\",\n" +
                "                \"visiorGroupId\": \"sadsa-1sfsdfsdfsdff\",\n" +
                "                \"visiorGroupName\": \"分组\",\n" +
                "                \"receptionistId\": \"3124126241412\",\n" +
                "                \"receptionistName\": \"王五\",\n" +
                "                \"receptionistCode\": \"2423O4U2O3\",\n" +
                "                \"visitPurpose\": \"参观\",\n" +
                "                \"visitStartTime\": \"2018-07-26T15:00:00+08:00\",\n" +
                "                \"visitEndTime\": \"2018-07-26T19:00:00+08:00\",\n" +
                "                \"QRCode\": \"2015468421\",\n" +
                "                \"certAddr\": \"江苏南京\",\n" +
                "                \"certIssuer\": \"派出所\",\n" +
                "                \"nation\": 1,\n" +
                "                \"birthplace\": \"江苏南京\",\n" +
                "                \"visitorWorkUnit\": \"海康威视\",\n" +
                "                \"orderId\": \"c1ou5th1p8chiicrcqcre\",\n" +
                "                \"visitorAddress\": \"湖南路\",\n" +
                "                \"personNum\": 1,\n" +
                "                \"plannedStartTime\": \"2018-07-26T15:00:00+08:00\",\n" +
                "                \"plannedEndTime\": \"2018-08-26T15:00:00+08:00\",\n" +
                "                \"designatedResources\": [\n" +
                "                    {\n" +
                "                        \"paramKey\": \"1\",\n" +
                "                        \"paramValues\": [\n" +
                "                            \"17c09845y1c05c79059c\"\n" +
                "                        ]\n" +
                "                    }\n" +
                "                ],\n" +
                "                \"cardNo\": \"2143v10v649u396uv099\",\n" +
                "                \"privilegeGroupNames\": [\n" +
                "                    \"111111111\"\n" +
                "                ]\n" +
                "            }\n" +
                "        ]\n" +
                "    }\n" +
                "}";

        com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(s);

        if ("0".equals(jsonObject.getString("code"))) {

            com.alibaba.fastjson.JSONObject data = jsonObject.getJSONObject("data");

            final com.alibaba.fastjson.JSONArray list = data.getJSONArray("list");

            for (int i = 0; i < list.size(); i++) {

                com.alibaba.fastjson.JSONObject jj = list.getJSONObject(i);

                String orderId = jj.getString("orderId");

                System.out.println(orderId);

            }
        }*/
        Map<String, String> stringStringMap = faceScore("1231");
        System.out.println(stringStringMap);

    }
}
